#include "TextureGLES.h"
#include "RendererGLES.h"

namespace Nezha
{

	void PixelBufferGLES::allocate()
	{
		if(mData)
		{
			return;
		}

		mData = NZMalloc(mSizeInBytes);
	}

	void PixelBufferGLES::deallocate()
	{
		if(mData)
		{
			NZFree(mData);
			mSizeInBytes = 0;
		}
	}

	TextureGLES::TextureGLES(HardwareBuffer::Usage usage, const _Image2D& img2d, bool createShadowBuffer,
		bool hasMipmap, bool isCompressed, RendererGLES* r)
		:Texture(usage, img2d.mFormat, img2d.mWidth, img2d.mHeight, 1, createShadowBuffer, hasMipmap, isCompressed)
		,mTexHandle(0)
		,mRenderer(r)
	{
		if(mUsingShadowBuffer && mShadowBuffer.sizeInBytes() == 0)
		{
			mShadowBuffer.resize(img2d.getSize());

			if(img2d.getData())
				mShadowBuffer.write(img2d.getData(), img2d.getSize());
		}
	}

	TextureGLES::~TextureGLES()
	{
		if(mTexHandle)
		{
			glDeleteTextures(1, &mTexHandle);
			GL_ERROR_DUMP(mRenderer->getAdaptor());
		}

		for(GLESMipmaps::iterator it = mMipmaps.begin(); it != mMipmaps.end(); it++)
		{
			(*it).deallocate();
		}
	}

	bool TextureGLES::prepare(const u8* data)
	{
		glGenTextures(1, &mTexHandle);
		GL_ERROR_DUMP(mRenderer->getAdaptor());

		glBindTexture(GL_TEXTURE_2D, mTexHandle);
		GLenum fmt = GLenumMapping::GLTexFormat(mFormat);
		glTexImage2D(GL_TEXTURE_2D, 0, fmt, mWidth, mHeight, 0, fmt, GL_UNSIGNED_BYTE , mUsingShadowBuffer ? mShadowBuffer.data() : data);
		GL_ERROR_DUMP(mRenderer->getAdaptor());

		// default
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, mHasMipmaps ? GL_NEAREST_MIPMAP_LINEAR : GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
		GL_ERROR_DUMP(mRenderer->getAdaptor());

		if(mHasMipmaps)
		{
			generateMipmaps();
		}

		return true;
	}

	// we use shadow buffer always
	void* TextureGLES::lockImpl(u32 offset, u32 length, LockOption opt)
	{
		NZ_ASSERT_EX(false, "Opengl es2 support no hardware buffer locking, please check the shadow buffer locking issue.");

		return NULL;
	}

	void TextureGLES::unlockImpl()
	{

	}

	void TextureGLES::syncShadowBuffer()
	{
		mRenderer->bindGLBuffer(GL_TEXTURE_2D, mTexHandle);

		glBindTexture(GL_TEXTURE_2D, mTexHandle);
		GLenum fmt = GLenumMapping::GLTexFormat(mFormat);
		glTexImage2D(GL_TEXTURE_2D, 0, fmt, mWidth, mHeight, 0, fmt, GL_UNSIGNED_BYTE , mShadowBuffer.data());
		GL_ERROR_DUMP(mRenderer->getAdaptor());
	}

	void TextureGLES::generateMipmaps()
	{
		// TODO
	}



	TextureManagerGLES::TextureManagerGLES(RendererGLES* r)
		:mRenderer(r)
	{

	}

	TexturePtr TextureManagerGLES::_create2DTexture(const _Image2D& img2d, bool mipmap, HardwareBuffer::Usage usage)
	{
		TexturePtr texPtr;

		// TODO determine if compressed by format
		bool isCompressed = false;

		bool isPowerOf2 = NZIsPowerOfTwo(img2d.mWidth) && NZIsPowerOfTwo(img2d.mHeight);

		if(!isPowerOf2)
		{
			// FIXME error or warnning?

			NZError("Tend to create nonpower2 sized texture.");
			return texPtr;
		}

		TextureGLES* tex = NZ_New TextureGLES(usage, img2d, usage == HardwareBuffer::HBU_DYNAMIC, mipmap, isCompressed, mRenderer);

		if(!tex->prepare(img2d.getData()))
		{
			NZ_Delete tex;
		}

		texPtr = tex;

		return texPtr;
	}

	void TextureManagerGLES::releaseTextureImpl(const TexturePtr& tex)
	{
		// do nothing.
	}

}//end namespace nezha